package http

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"math"
	"math/rand"
	"net/http"
	"sort"
	"sync"
	"time"

	"github.com/fatih/color"
)

// RampUpStep 加压步骤配置
type RampUpStep struct {
	IncrementThreads int           // 相对于当前线程数增加的数量
	Duration         time.Duration // 完成此增量所需的时间
}

// Endpoint 接口配置 - 支持GET和POST
type Endpoint struct {
	Method  string            // 请求方法: GET, POST
	URL     string            // 接口URL
	Body    interface{}       // POST请求体
	Headers map[string]string // 请求头
	Weight  int               // 权重，用于分配请求比例
}

// Config 压测配置参数
type Config struct {
	InitialThreads   int           // 初始线程数
	RampUpSteps      []RampUpStep  // 加压步骤配置，每个步骤包含增加的线程数和持续时间
	StableTime       time.Duration // 稳定运行时间
	ThreadsPerStep   int           // 每次减少的线程数
	RampDownTime     time.Duration // 减压总时间
	Endpoints        []Endpoint    // 接口列表，支持多个GET/POST
	RequestTimeout   time.Duration // 请求超时时间
	StatsInterval    time.Duration // 统计输出间隔
	SkipTLSVerify    bool          // 是否跳过TLS验证
	TargetThroughput float64       // 目标吞吐量（每分钟请求数）
}

// RequestResult 请求结果
type RequestResult struct {
	duration   time.Duration
	success    bool
	statusCode int
	endpoint   string // 记录请求的接口
	timestamp  time.Time
}

// Stats 统计数据
type Stats struct {
	mu                 sync.RWMutex
	totalRequests      int64
	totalErrors        int64
	totalDuration      time.Duration
	responseTimes      []time.Duration
	throughputCounter  int64
	tps                float64
	lastThroughputTime time.Time
	currentPhase       string
	currentThreads     int
	startTime          time.Time
	endpointStats      map[string]*EndpointStats // 按接口统计
}

// EndpointStats 接口单独统计
type EndpointStats struct {
	Requests   int64
	Errors     int64
	Duration   time.Duration
	StatusCode map[int]int64 // 状态码统计
}

// TestContext 压测上下文，包含所有压测过程中需要的组件
type TestContext struct {
	config          *Config
	stats           *Stats
	resultsChan     chan RequestResult
	stopChan        chan struct{}
	workerStopChans []chan struct{}
	httpClient      *http.Client
}

// NewStats 初始化统计数据
func NewStats(endpoints []Endpoint) *Stats {
	endpointStats := make(map[string]*EndpointStats)
	for _, ep := range endpoints {
		key := fmt.Sprintf("%s %s", ep.Method, ep.URL)
		endpointStats[key] = &EndpointStats{
			StatusCode: make(map[int]int64),
		}
	}

	return &Stats{
		responseTimes:      make([]time.Duration, 0),
		lastThroughputTime: time.Now(),
		startTime:          time.Now(),
		currentPhase:       "准备中",
		currentThreads:     0,
		endpointStats:      endpointStats,
	}
}

// RecordResult 记录请求结果
func (s *Stats) RecordResult(result RequestResult) {
	s.mu.Lock()
	defer s.mu.Unlock()

	// 更新全局统计
	s.totalRequests++
	s.totalDuration += result.duration
	s.responseTimes = append(s.responseTimes, result.duration)
	s.throughputCounter++

	if !result.success || result.statusCode >= 400 {
		s.totalErrors++
	}

	// 更新接口单独统计
	key := result.endpoint
	if epStats, exists := s.endpointStats[key]; exists {
		epStats.Requests++
		epStats.Duration += result.duration
		epStats.StatusCode[result.statusCode]++

		if !result.success || result.statusCode >= 400 {
			epStats.Errors++
		}
	}
}

// UpdatePhaseInfo 更新当前阶段信息
func (s *Stats) UpdatePhaseInfo(phase string, threads int) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.currentPhase = phase
	s.currentThreads = threads
}

// CalculateStats 计算并返回当前统计数据
func (s *Stats) CalculateStats() (map[string]interface{}, []time.Duration) {
	s.mu.RLock()
	defer s.mu.RUnlock()

	now := time.Now()
	elapsed := now.Sub(s.lastThroughputTime).Seconds()

	// 计算TPS
	if elapsed > 0 {
		s.tps = float64(s.throughputCounter) / elapsed
	} else {
		s.tps = 0
	}

	// 复制当前状态用于返回
	currentPhase := s.currentPhase
	currentThreads := s.currentThreads
	totalRequests := s.totalRequests
	totalErrors := s.totalErrors
	totalDuration := s.totalDuration
	runTime := now.Sub(s.startTime)

	// 重置吞吐量计数器
	s.throughputCounter = 0
	s.lastThroughputTime = now

	// 复制响应时间切片用于计算百分位数
	rtCopy := make([]time.Duration, len(s.responseTimes))
	copy(rtCopy, s.responseTimes)

	// 计算错误率
	errorRate := 0.0
	if totalRequests > 0 {
		errorRate = float64(totalErrors) / float64(totalRequests)
	}

	// 计算平均响应时间
	avgResponseTime := time.Duration(0)
	if totalRequests > 0 {
		avgResponseTime = totalDuration / time.Duration(totalRequests)
	}

	return map[string]interface{}{
		"total_requests":    totalRequests,
		"total_errors":      totalErrors,
		"error_rate":        errorRate,
		"avg_response_time": avgResponseTime,
		"tps":               s.tps,
		"current_phase":     currentPhase,
		"current_threads":   currentThreads,
		"run_time":          runTime,
	}, rtCopy
}

// 计算指定百分位数的响应时间
func calculatePercentile(times []time.Duration, percentile float64) time.Duration {
	if len(times) == 0 {
		return 0
	}

	sort.Slice(times, func(i, j int) bool {
		return times[i] < times[j]
	})

	index := int(math.Ceil(percentile/100.0*float64(len(times)))) - 1
	if index < 0 {
		index = 0
	}

	return times[index]
}

// 选择要请求的接口（基于权重）
func selectEndpoint(endpoints []Endpoint) Endpoint {
	if len(endpoints) == 1 {
		return endpoints[0]
	}

	// 计算总权重
	totalWeight := 0
	for _, ep := range endpoints {
		totalWeight += ep.Weight
	}

	// 随机选择
	r := rand.Intn(totalWeight)
	current := 0
	for _, ep := range endpoints {
		current += ep.Weight
		if r < current {
			return ep
		}
	}

	return endpoints[0] //  fallback
}

// 执行HTTP请求（支持GET和POST）
func makeHTTPRequest(client *http.Client, endpoint Endpoint) (time.Duration, bool, int) {
	start := time.Now()
	var req *http.Request
	var err error

	// 创建请求
	switch endpoint.Method {
	case http.MethodGet:
		req, err = http.NewRequest(http.MethodGet, endpoint.URL, nil)
	case http.MethodPost:
		// 处理POST请求体
		var body io.Reader
		if endpoint.Body != nil {
			jsonBody, err := json.Marshal(endpoint.Body)
			if err != nil {
				return time.Since(start), false, 0
			}
			body = bytes.NewBuffer(jsonBody)
		}
		req, err = http.NewRequest(http.MethodPost, endpoint.URL, body)
	default:
		return time.Since(start), false, 0
	}

	if err != nil {
		return time.Since(start), false, 0
	}

	// 设置请求头
	req.Header.Set("Content-Type", "application/json")
	for k, v := range endpoint.Headers {
		req.Header.Set(k, v)
	}

	// 发送请求
	resp, err := client.Do(req)
	duration := time.Since(start)

	if err != nil {
		return duration, false, 0
	}
	defer func(Body io.ReadCloser) {
		err := Body.Close()
		if err != nil {
			fmt.Println("Error closing body")
		}
	}(resp.Body)

	// 读取响应体
	_, _ = io.ReadAll(resp.Body)

	// 2xx状态码视为成功
	success := resp.StatusCode >= 200 && resp.StatusCode < 300
	return duration, success, resp.StatusCode
}

// 工作线程函数
func worker(ctx *TestContext, results chan<- RequestResult, stopChan <-chan struct{}) {
	for {
		select {
		case <-stopChan:
			return
		default:
			// 选择一个接口
			endpoint := selectEndpoint(ctx.config.Endpoints)
			endpointKey := fmt.Sprintf("%s %s", endpoint.Method, endpoint.URL)

			// 发送请求
			duration, success, statusCode := makeHTTPRequest(ctx.httpClient, endpoint)

			// 记录结果
			results <- RequestResult{
				duration:   duration,
				success:    success,
				statusCode: statusCode,
				endpoint:   endpointKey,
				timestamp:  time.Now(),
			}
		}
	}
}

// 清除当前控制台行
func clearConsoleLines(lines int) {
	// 移动光标到指定行并清除
	for i := 0; i < lines; i++ {
		fmt.Print("\033[1A\033[K") // 上移一行并清除
	}
}

// 打印实时统计信息
func printRealtimeStats(ctx *TestContext) {
	statsMap, times := ctx.stats.CalculateStats()

	if statsMap["total_requests"].(int64) == 0 {
		return
	}

	p99 := calculatePercentile(times, 99)
	p95 := calculatePercentile(times, 95)
	p50 := calculatePercentile(times, 50)

	// 彩色输出
	phaseColor := color.New(color.FgCyan).SprintFunc()
	statColor := color.New(color.FgGreen).SprintFunc()
	errorColor := color.New(color.FgRed).SprintFunc()

	fmt.Println("========================================")
	fmt.Printf("压测状态: %s\n", phaseColor(statsMap["current_phase"]))
	fmt.Printf("当前线程数: %d\n", statsMap["current_threads"])
	fmt.Printf("运行时间: %v\n", statsMap["run_time"])
	fmt.Println("----------------------------------------")
	fmt.Printf("总请求数: %s\n", statColor(statsMap["total_requests"]))
	fmt.Printf("错误数: %s (错误率: %.2f%%)\n",
		errorColor(statsMap["total_errors"]),
		statsMap["error_rate"].(float64)*100)
	fmt.Printf("平均响应时间: %v\n", statsMap["avg_response_time"])
	fmt.Printf("响应时间分位数: P99=%v, P95=%v, P50=%v\n",
		p99, p95, p50)
	fmt.Printf("当前TPS: %s\n", statColor(fmt.Sprintf("%.2f", statsMap["tps"])))
	fmt.Println("========================================")
}

// 实时更新统计信息循环
func realtimeStatsLoop(ctx *TestContext) {
	// 首次输出不需要清除
	firstRun := true
	linesToClear := 10 // 要清除的行数

	for {
		select {
		case <-time.Tick(ctx.config.StatsInterval):
			if !firstRun {
				clearConsoleLines(linesToClear)
			}
			firstRun = false
			printRealtimeStats(ctx)
		case <-ctx.stopChan:
			return
		}
	}
}

// 处理结果并更新统计
func processResultsLoop(ctx *TestContext) {
	for {
		select {
		case <-ctx.stopChan:
			return
		case result := <-ctx.resultsChan:
			ctx.stats.RecordResult(result)
		}
	}
}

// 初始化HTTP客户端
func initHTTPClient(config *Config) *http.Client {
	transport := &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: config.SkipTLSVerify, // 跳过TLS验证
		},
	}

	return &http.Client{
		Timeout:   config.RequestTimeout,
		Transport: transport,
	}
}

// 初始化压测上下文
func initTestContext(config *Config) *TestContext {
	return &TestContext{
		config:          config,
		stats:           NewStats(config.Endpoints),
		resultsChan:     make(chan RequestResult, config.InitialThreads*2),
		stopChan:        make(chan struct{}),
		workerStopChans: make([]chan struct{}, 0, config.InitialThreads),
		httpClient:      initHTTPClient(config),
	}
}

// 启动初始线程
func startInitialThreads(ctx *TestContext) {
	config := ctx.config
	ctx.stats.UpdatePhaseInfo("初始化", 0)

	// 启动初始线程
	for i := 0; i < config.InitialThreads; i++ {
		workerStop := make(chan struct{})
		ctx.workerStopChans = append(ctx.workerStopChans, workerStop)
		go worker(ctx, ctx.resultsChan, workerStop)
	}

	currentThreads := len(ctx.workerStopChans)
	ctx.stats.UpdatePhaseInfo("初始运行", currentThreads)
	fmt.Printf("已启动初始线程数: %d\n", currentThreads)
}

// 启动辅助协程（结果处理和统计打印）
func startAuxiliaryGoroutines(ctx *TestContext) {
	// 启动结果处理协程
	go processResultsLoop(ctx)

	// 启动实时统计协程
	go realtimeStatsLoop(ctx)
}

// 执行加压阶段 - 基于当前线程数递增
func runRampUpPhase(ctx *TestContext) {
	config := ctx.config
	currentThreads := len(ctx.workerStopChans)

	// 遍历每步加压配置
	for stepIdx, step := range config.RampUpSteps {
		increment := step.IncrementThreads
		duration := step.Duration

		if increment <= 0 {
			fmt.Printf("警告: 第%d步增加的线程数必须为正数，将跳过\n", stepIdx+1)
			continue
		}

		// 计算目标线程数（当前 + 增量）
		targetThreads := currentThreads + increment
		fmt.Printf("开始第%d步加压: 从%d到%d线程，将在%s内完成\n",
			stepIdx+1, currentThreads, targetThreads, duration)

		// 设置当前阶段
		ctx.stats.UpdatePhaseInfo(fmt.Sprintf("加压阶段 %d/%d", stepIdx+1, len(config.RampUpSteps)), currentThreads)

		// 计算需要的增加次数和每次增加的线程数
		stepInterval := 500 * time.Millisecond // 线程增加的间隔
		stepsNeeded := int(duration / stepInterval)
		if stepsNeeded <= 0 {
			stepsNeeded = 1 // 至少一步
		}

		// 计算每次增加的线程数
		threadsPerIncrement := increment / stepsNeeded
		remainingThreads := increment % stepsNeeded

		// 逐步增加线程
		for i := 0; i < stepsNeeded; i++ {
			// 计算本次要增加的线程数（处理余数）
			currentIncrement := threadsPerIncrement
			if i < remainingThreads {
				currentIncrement++
			}

			if currentIncrement <= 0 {
				time.Sleep(stepInterval)
				continue
			}

			// 启动新线程
			for j := 0; j < currentIncrement; j++ {
				workerStop := make(chan struct{})
				ctx.workerStopChans = append(ctx.workerStopChans, workerStop)
				go worker(ctx, ctx.resultsChan, workerStop)
			}

			// 更新当前线程数
			currentThreads = len(ctx.workerStopChans)
			ctx.stats.UpdatePhaseInfo(fmt.Sprintf("加压阶段 %d/%d", stepIdx+1, len(config.RampUpSteps)), currentThreads)

			// 检查是否已达到目标
			if currentThreads >= targetThreads {
				break
			}

			// 等待下一步
			time.Sleep(stepInterval)
		}

		fmt.Printf("完成第%d步加压: 当前线程数%d\n", stepIdx+1, currentThreads)
	}
}

// 执行稳定运行阶段
func runStablePhase(ctx *TestContext) {
	currentThreads := len(ctx.workerStopChans)
	ctx.stats.UpdatePhaseInfo("稳定阶段", currentThreads)
	fmt.Printf("开始稳定运行阶段，持续%v，当前线程数%d\n", ctx.config.StableTime, currentThreads)
	time.Sleep(ctx.config.StableTime)
}

// 执行减压阶段
func runRampDownPhase(ctx *TestContext) {
	config := ctx.config
	currentThreads := len(ctx.workerStopChans)
	ctx.stats.UpdatePhaseInfo("减压阶段", currentThreads)

	steps := currentThreads / config.ThreadsPerStep
	if currentThreads%config.ThreadsPerStep != 0 {
		steps++
	}
	rampDownInterval := config.RampDownTime / time.Duration(steps)

	for i := 0; i < steps; i++ {
		threadsToStop := config.ThreadsPerStep
		if len(ctx.workerStopChans) < threadsToStop {
			threadsToStop = len(ctx.workerStopChans)
		}

		if threadsToStop <= 0 {
			break
		}

		// 停止指定数量的线程
		for j := 0; j < threadsToStop; j++ {
			close(ctx.workerStopChans[0])
			ctx.workerStopChans = ctx.workerStopChans[1:]
		}

		currentThreads := len(ctx.workerStopChans)
		ctx.stats.UpdatePhaseInfo("减压阶段", currentThreads)
		fmt.Printf("减压进度: 第%d步，当前线程数: %d\n",
			i+1, currentThreads)

		// 最后一步不需要等待
		if i < steps-1 && len(ctx.workerStopChans) > 0 {
			time.Sleep(rampDownInterval)
		}
	}
}

// 打印最终统计结果
func printFinalStats(ctx *TestContext) {
	// 清除实时统计信息
	clearConsoleLines(10)

	fmt.Println("========================================")
	fmt.Println("压测完成，最终统计结果:")
	fmt.Println("----------------------------------------")

	statsMap, times := ctx.stats.CalculateStats()

	p99 := calculatePercentile(times, 99)
	p95 := calculatePercentile(times, 95)
	p50 := calculatePercentile(times, 50)

	fmt.Printf("总运行时间: %v\n", statsMap["run_time"])
	fmt.Printf("总请求数: %d\n", statsMap["total_requests"])
	fmt.Printf("总错误数: %d (错误率: %.2f%%)\n",
		statsMap["total_errors"],
		statsMap["error_rate"].(float64)*100)
	fmt.Printf("平均响应时间: %v\n", statsMap["avg_response_time"])
	fmt.Printf("响应时间分位数: P99=%v, P95=%v, P50=%v\n",
		p99, p95, p50)
	fmt.Printf("平均TPS: %.2f\n",
		float64(statsMap["total_requests"].(int64))/
			statsMap["run_time"].(time.Duration).Seconds())

	// 打印各接口的统计
	fmt.Println("\n接口详细统计:")
	ctx.stats.mu.RLock()
	for ep, epStats := range ctx.stats.endpointStats {
		errorRate := 0.0
		if epStats.Requests > 0 {
			errorRate = float64(epStats.Errors) / float64(epStats.Requests)
		}

		avgDuration := time.Duration(0)
		if epStats.Requests > 0 {
			avgDuration = epStats.Duration / time.Duration(epStats.Requests)
		}

		fmt.Printf("- %s:\n", ep)
		fmt.Printf("  请求数: %d, 错误率: %.2f%%, 平均响应: %v\n",
			epStats.Requests, errorRate*100, avgDuration)
		fmt.Printf("  状态码分布: ")
		for code, count := range epStats.StatusCode {
			fmt.Printf("%d:%d ", code, count)
		}
		fmt.Println()
	}
	ctx.stats.mu.RUnlock()

	fmt.Println("========================================")
}

// 验证配置参数
func validateConfig(config *Config) bool {
	if config.InitialThreads <= 0 {
		fmt.Println("错误: 初始线程数必须大于0")
		return false
	}
	if len(config.RampUpSteps) == 0 {
		fmt.Println("错误: 至少需要配置一个加压步骤")
		return false
	}

	// 验证加压步骤
	for i, step := range config.RampUpSteps {
		if step.IncrementThreads <= 0 {
			fmt.Printf("错误: 第%d步增加的线程数必须大于0\n", i+1)
			return false
		}
		if step.Duration <= 0 {
			fmt.Printf("错误: 第%d步持续时间必须大于0\n", i+1)
			return false
		}
	}

	if len(config.Endpoints) == 0 {
		fmt.Println("错误: 至少需要配置一个接口")
		return false
	}
	for i, ep := range config.Endpoints {
		if ep.Method != http.MethodGet && ep.Method != http.MethodPost {
			fmt.Printf("错误: 接口 %d 只支持GET和POST方法\n", i)
			return false
		}
		if ep.URL == "" {
			fmt.Printf("错误: 接口 %d 的URL不能为空\n", i)
			return false
		}
		if ep.Weight <= 0 {
			// 权重默认为1
			config.Endpoints[i].Weight = 1
		}
	}
	if config.ThreadsPerStep <= 0 {
		fmt.Println("错误: 每次减少的线程数必须大于0")
		return false
	}
	if config.StableTime < 0 {
		fmt.Println("错误: 稳定时间不能为负数")
		return false
	}
	if config.RampDownTime < 0 {
		fmt.Println("错误: 减压时间不能为负数")
		return false
	}
	return true
}

// 打印配置信息
func printConfig(config *Config) {
	fmt.Println("压测配置:")
	fmt.Printf("  初始线程数: %d\n", config.InitialThreads)
	fmt.Println("  加压步骤:")
	current := config.InitialThreads
	for i, step := range config.RampUpSteps {
		current += step.IncrementThreads
		fmt.Printf("    第%d步: +%d线程 (持续%s) → 总计%d\n",
			i+1, step.IncrementThreads, step.Duration, current)
	}
	fmt.Printf("  稳定运行时间: %v\n", config.StableTime)
	fmt.Printf("  每次减少线程数: %d\n", config.ThreadsPerStep)
	fmt.Printf("  减压时间: %v\n", config.RampDownTime)
	fmt.Println("  测试接口:")
	for _, ep := range config.Endpoints {
		fmt.Printf("    %s %s (权重: %d)\n", ep.Method, ep.URL, ep.Weight)
	}
	fmt.Println("----------------------------------------")
	fmt.Println("按Ctrl+C停止压测")
	fmt.Println("开始压测...")
	time.Sleep(2 * time.Second)
	// 清除配置信息，为实时统计腾出空间
	clearConsoleLines(10 + len(config.Endpoints) + len(config.RampUpSteps))
}

// 主压测流程
func runLoadTest(config *Config) {
	// 验证配置
	if !validateConfig(config) {
		return
	}

	// 打印配置
	printConfig(config)

	// 初始化随机数
	rand.New(rand.NewSource(time.Now().UnixNano()))

	// 初始化上下文
	ctx := initTestContext(config)
	defer close(ctx.stopChan)

	// 启动辅助协程
	startAuxiliaryGoroutines(ctx)

	// 启动初始线程
	startInitialThreads(ctx)

	// 等待初始线程稳定
	time.Sleep(5 * time.Second)

	// 执行加压阶段
	runRampUpPhase(ctx)

	// 执行稳定运行阶段
	runStablePhase(ctx)

	// 执行减压阶段
	runRampDownPhase(ctx)

	// 等待所有请求完成
	time.Sleep(config.RequestTimeout)

	// 打印最终统计
	printFinalStats(ctx)
}
